package cn.janyd.action.ui;

import cn.janyd.action.ConfigBuilder;
import cn.janyd.action.converter.DateType;
import com.intellij.ide.util.PackageChooserDialog;
import com.intellij.ide.util.TreeClassChooser;
import com.intellij.ide.util.TreeClassChooserFactory;
import com.intellij.openapi.fileChooser.FileChooser;
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.JavaPsiFacade;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiPackage;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.ui.components.JBCheckBox;
import com.intellij.ui.components.JBTextField;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;
import java.util.Objects;

/**
 * @author janyd
 * @since 2020/8/7 13:14
 */
public class GeneratorDialog extends DialogWrapper {

    private final static String DATE = "java.util.Date";

    private final static String LOCAL_DATE_TIME = "java.time.LocalDateTime";


    private JPanel mainPanel;
    private JBTextField dataObjectPackageField;
    private JButton dataObjectPackageBtn;
    private JBTextField mapperPathField;
    private JButton mapperPathBtn;
    private JBTextField superClassField;
    private JButton superClassBtn;
    private JBCheckBox lombokCb;
    private JBCheckBox mybatisPlusAnnotationCb;
    private JBTextField mapperXmlPathField;
    private JButton mapperXmlPathBtn;
    private JBCheckBox swaggerCb;
    private JBCheckBox superClassCb;
    private JBCheckBox mapperPathCb;
    private JBCheckBox mapperXmlPathCb;
    private JComboBox<String> dateTypeCombo;
    private JBCheckBox lombokAccessorsCb;
    private JComboBox<ModuleItem> dataObjectModuleCombo;
    private JComboBox<ModuleItem> mapperModuleCombo;
    private JBTextField suffixField;
    private JBTextField tablePrefix;

    private final Project project;

    public GeneratorDialog(@Nullable Project project) {
        super(project);
        this.project = project;
        initBtn();
        initCombo();
        init();
    }

    @Override
    protected @Nullable
    JComponent createCenterPanel() {
        return mainPanel;
    }

    @Override
    protected void doOKAction() {
        if (StringUtils.isBlank(getDataObjectPackage())) {
            Messages.showMessageDialog(project, "请选择DataObject父类", "Generate Failed", null);
            dataObjectPackageField.requestFocus();
            return;
        }

        if (superClassCb.isSelected() && getSuperClass() == null) {
            Messages.showMessageDialog(project, "请选择DataObject父类", "Generate Failed", null);
            superClassField.requestFocus();
            return;
        }

        if (mapperPathCb.isSelected() && StringUtils.isBlank(getMapperPath())) {
            Messages.showMessageDialog(project, "请选择生成Mapper包路径", "Generate Failed", null);
            mapperPathField.requestFocus();
            return;
        }

        if (mapperXmlPathCb.isSelected() && StringUtils.isBlank(getMapperXmlPath())) {
            Messages.showMessageDialog(project, "请选择生成Mapper.xml路径", "Generate Failed", null);
            mapperXmlPathField.requestFocus();
            return;
        }


        close(0);
    }

    public String getDataObjectPackage() {
        return dataObjectPackageField.getText();
    }

    public String getMapperPath() {
        return mapperPathField.getText();
    }

    public String getMapperXmlPath() {
        return mapperXmlPathField.getText();
    }

    public boolean getLombok() {
        return lombokCb.isSelected();
    }

    public boolean getLombokAccessors() {
        return lombokCb.isSelected() && lombokAccessorsCb.isSelected();
    }

    public boolean getSwagger() {
        return swaggerCb.isSelected();
    }

    public boolean getMybatisPlusAnnotation() {
        return mybatisPlusAnnotationCb.isSelected();
    }

    public PsiClass getSuperClass() {
        if (StringUtils.isBlank(superClassField.getText())) {
            return null;
        }
        JavaPsiFacade javaPsiFacade = JavaPsiFacade.getInstance(project);
        return javaPsiFacade.findClass(superClassField.getText(), GlobalSearchScope.allScope(project));
    }

    public DateType getDateType() {
        final String selectedItem = (String) dateTypeCombo.getSelectedItem();

        if (DATE.equals(selectedItem)) {
            return DateType.ONLY_DATE;
        } else if (LOCAL_DATE_TIME.equals(selectedItem)) {
            return DateType.TIME_PACK;
        } else {
            return DateType.ONLY_DATE;
        }
    }

    public ConfigBuilder getConfigBuilder() {
        ConfigBuilder configBuilder = new ConfigBuilder()
                .setDataObjectPackage(dataObjectPackageField.getText())
                .setEnableSuperClass(superClassCb.isSelected())
                .setEnableMapper(mapperPathCb.isSelected())
                .setEnableMapperXml(mapperXmlPathCb.isSelected())
                .setLombok(lombokCb.isSelected())
                .setLombokAccessors(lombokAccessorsCb.isSelected())
                .setSwagger(swaggerCb.isSelected())
                .setMybatisPlusAnnotation(mybatisPlusAnnotationCb.isSelected())
                .setDataObjectSuffix(suffixField.getText())
                .setTablePrefix(tablePrefix.getText())
                .setDateType(this.getDateType());

        if (configBuilder.isEnableSuperClass() && StringUtils.isNotBlank(superClassField.getText())) {
            JavaPsiFacade javaPsiFacade = JavaPsiFacade.getInstance(project);
            configBuilder.setSuperClass(javaPsiFacade.findClass(superClassField.getText(), GlobalSearchScope.allScope(project)));
        }

        if (configBuilder.isEnableMapper()) {
            configBuilder.setMapperPackage(mapperPathField.getText());
        }

        if (configBuilder.isEnableMapperXml()) {
            configBuilder.setMapperXmlPath(mapperXmlPathField.getText());
        }
        ModuleItem moduleItem = (ModuleItem) dataObjectModuleCombo.getSelectedItem();
        configBuilder.setDataObjectModulePath(ModuleRootManager.getInstance(moduleItem.getModule()).getContentRoots()[0].getPath());
        if (configBuilder.isEnableMapper()) {
            moduleItem = (ModuleItem) mapperModuleCombo.getSelectedItem();
            configBuilder.setMapperModulePath(ModuleRootManager.getInstance(moduleItem.getModule()).getContentRoots()[0].getPath());
        }
        return configBuilder.init();
    }

    private void initBtn() {
        dataObjectPackageBtn.addActionListener(e -> {
            ModuleItem moduleItem = (ModuleItem) dataObjectModuleCombo.getSelectedItem();
            PackageChooserDialog packageChooser = new PackageChooserDialog("选择生成Data Object目录", moduleItem.getModule());
            packageChooser.show();
            PsiPackage psiPackage = packageChooser.getSelectedPackage();
            if (Objects.nonNull(psiPackage)) {
                dataObjectPackageField.setText(psiPackage.getQualifiedName());
            }
        });

        superClassBtn.addActionListener(e -> {
            TreeClassChooserFactory treeClassChooserFactory = TreeClassChooserFactory.getInstance(project);
            TreeClassChooser chooser = treeClassChooserFactory.createAllProjectScopeChooser("选择生成Data Object父类");
            chooser.showDialog();
            if (Objects.nonNull(chooser.getSelected())) {
                final PsiClass superClass = chooser.getSelected();
                superClassField.setText(superClass.getQualifiedName());
            }
        });

        mapperPathBtn.addActionListener(e -> {
            ModuleItem moduleItem = (ModuleItem) dataObjectModuleCombo.getSelectedItem();
            PackageChooserDialog packageChooser = new PackageChooserDialog("选择生成Mapper目录", moduleItem.getModule());
            packageChooser.show();
            PsiPackage psiPackage = packageChooser.getSelectedPackage();
            if (Objects.nonNull(psiPackage)) {
                mapperPathField.setText(psiPackage.getQualifiedName());
            }
        });

        mapperXmlPathBtn.addActionListener(e -> {
            FileChooserDescriptor descriptor = new FileChooserDescriptor(false, true, false, false, false, false);
            VirtualFile virtualFile = FileChooser.chooseFile(descriptor, project, null);
            if (Objects.nonNull(virtualFile)) {
                mapperXmlPathField.setText(virtualFile.getPath());
            }
        });


        superClassCb.addItemListener(e -> {
            final JCheckBox item = (JCheckBox) e.getItem();
            final boolean selected = item.isSelected();
            superClassBtn.setEnabled(selected);
            superClassField.setEnabled(selected);
        });

        mapperPathCb.addItemListener(e -> {
            final JCheckBox item = (JCheckBox) e.getItem();
            final boolean selected = item.isSelected();
            mapperPathBtn.setEnabled(selected);
            mapperPathField.setEnabled(selected);
        });

        mapperXmlPathCb.addItemListener(e -> {
            final JCheckBox item = (JCheckBox) e.getItem();
            final boolean selected = item.isSelected();
            mapperXmlPathBtn.setEnabled(selected);
            mapperXmlPathField.setEnabled(selected);
        });

    }

    private void initCombo() {
        dateTypeCombo.addItem("java.util.Date");
        dateTypeCombo.addItem("java.time.LocalDateTime");

        Module[] modules = ModuleManager.getInstance(project).getModules();
        for (Module module : modules) {
            ModuleItem moduleItem = new ModuleItem(module.getName(), module);
            dataObjectModuleCombo.addItem(moduleItem);
            mapperModuleCombo.addItem(moduleItem);
        }
    }

    @Data
    public static class ModuleItem {

        private String moduleName;

        private Module module;


        public ModuleItem(String moduleName, @NotNull Module module) {
            this.moduleName = moduleName;
            this.module = module;
        }

        @Override
        public String toString() {
            return this.moduleName;
        }
    }

}
